// 版权所有2012 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 此文件实现表达式的类型检查。

package types

import (
	"fmt"
	"go/ast"
	"go/constant"
	"go/internal/typeparams"
	"go/token"
	"math"
)

/*
Basic algorithm:

Expressions are checked recursively, top down. Expression checker functions
are generally of the form:

  func f(x *operand, e *ast.Expr, ...)

where e is the expression to be checked, and x is the result of the check.
The check performed by f may fail in which case x.mode == invalid, and
related error messages will have been issued by f.

If a hint argument is present, it is the composite literal element type
of an outer composite literal; it is used to type-check composite literal
elements that have no explicit type specification in the source
(e.g.: []T{{...}, {...}}, the hint is the type T in this case).

All expressions are checked via rawExpr, which dispatches according
to expression kind. Upon returning, rawExpr is recording the types and
constant values for all expressions that have an untyped type (those types
may change on the way up in the expression tree). Usually these are constants,
but the results of comparisons or non-constant shifts of untyped constants
may also be untyped, but not constant.

Untyped expressions may eventually become fully typed (i.e., not untyped),
typically when the value is assigned to a variable, or is used otherwise.
The updateExprType method is used to record this final type and update
the recorded types: the type-checked expression tree is again traversed down,
and the new type is propagated as needed. Untyped constant expression values
that become fully typed must now be representable by the full type (constant
sub-expression trees are left alone except for their roots). This mechanism
ensures that a client sees the actual (run-time) type an untyped value would
have. It also permits type-checking of lhs shift operands "as if the shift
were not present": when updateExprType visits an untyped lhs shift operand
and assigns it it's final type, that type must be an integer type, and a
constant lhs must be representable as an integer.

When an expression gets its final type, either on the way out from rawExpr,
on the way down in updateExprType, or at the end of the type checker run,
the type (and constant value, if any) is recorded via Info.Types, if present.
*/

type opPredicates map[token.Token]func(Type) bool

var unaryOpPredicates opPredicates

func init() {
	// 在init中设置unaryOpPredicates可以避免声明周期。
	unaryOpPredicates = opPredicates{
		token.ADD: isNumeric,
		token.SUB: isNumeric,
		token.XOR: isInteger,
		token.NOT: isBoolean,
	}
}

func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
	if pred := m[op]; pred != nil {
		if !pred(x.typ) {
			check.invalidOp(x, _UndefinedOp, "operator %s not defined for %s", op, x)
			return false
		}
	} else {
		check.invalidAST(x, "unknown operator %s", op)
		return false
	}
	return true
}

// 溢出检查常量x是否可由其类型表示。
// 对于非类型化常量，它检查该值是否没有变为
// 任意大。
func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
	assert(x.mode == constant_)

	if x.val.Kind() == constant.Unknown {
		// TODO（gri）我们应该准确报告出了什么问题。在
		// 当我们没有（go/constant）API时。
		// 另请参见go/constant/value.go中的TODO。
		check.errorf(atPos(opPos), _InvalidConstVal, "constant result is not representable")
		return
	}

	// 类型化常量必须在中表示
	// 它们在每次持续操作后的类型。
	if isTyped(x.typ) {
		check.representable(x, asBasic(x.typ))
		return
	}

	// 非类型化整数值不能任意增长。
	const prec = 512 // 512是恒定精度
	if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
		check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", opName(x.expr))
		x.val = constant.MakeUnknown()
	}
}

// opName返回操作的名称或空字符串。
// 目前，只处理可能溢出的操作。
// TODO（gri）将其扩展为命名
// 节点？
func opName(e ast.Expr) string {
	switch e := e.(type) {
	case *ast.BinaryExpr:
		if int(e.Op) < len(op2str2) {
			return op2str2[e.Op]
		}
	case *ast.UnaryExpr:
		if int(e.Op) < len(op2str1) {
			return op2str1[e.Op]
		}
	}
	return ""
}

var op2str1 = [...]string{
	token.XOR: "bitwise complement",
}

// 这仅用于可能导致溢出的操作。
var op2str2 = [...]string{
	token.ADD: "addition",
	token.SUB: "subtraction",
	token.XOR: "bitwise XOR",
	token.MUL: "multiplication",
	token.SHL: "shift",
}

// 一元表达式e可以是零。它只是为了更好地传递错误消息而传入的。
func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
	check.expr(x, e.X)
	if x.mode == invalid {
		return
	}
	switch e.Op {
	case token.AND:
		// 规范：“作为可寻址性的例外
		// 需求x也可以是复合文字。”
		if _, ok := unparen(e.X).(*ast.CompositeLit); !ok && x.mode != variable {
			check.invalidOp(x, _UnaddressableOperand, "cannot take address of %s", x)
			x.mode = invalid
			return
		}
		x.mode = value
		x.typ = &Pointer{base: x.typ}
		return

	case token.ARROW:
		typ := asChan(x.typ)
		if typ == nil {
			check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
			x.mode = invalid
			return
		}
		if typ.dir == SendOnly {
			check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x)
			x.mode = invalid
			return
		}
		x.mode = commaok
		x.typ = typ.elem
		check.hasCallOrRecv = true
		return
	}

	if !check.op(unaryOpPredicates, x, e.Op) {
		x.mode = invalid
		return
	}

	if x.mode == constant_ {
		if x.val.Kind() == constant.Unknown {
			// 无需执行任何操作（并且不要在溢出检查中导致以下错误）
			return
		}
		var prec uint
		if isUnsigned(x.typ) {
			prec = uint(check.conf.sizeof(x.typ) * 8)
		}
		x.val = constant.UnaryOp(e.Op, x.val, prec)
		x.expr = e
		check.overflow(x, e.Op, x.Pos())
		return
	}

	x.mode = value
	// x、 类型保持不变
}

func isShift(op token.Token) bool {
	return op == token.SHL || op == token.SHR
}

func isComparison(op token.Token) bool {
	// 注意：代币的订购不是为了让这更容易
	switch op {
	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
		return true
	}
	return false
}

func fitsFloat32(x constant.Value) bool {
	f32, _ := constant.Float32Val(x)
	f := float64(f32)
	return !math.IsInf(f, 0)
}

func roundFloat32(x constant.Value) constant.Value {
	f32, _ := constant.Float32Val(x)
	f := float64(f32)
	if !math.IsInf(f, 0) {
		return constant.MakeFloat64(f)
	}
	return nil
}

func fitsFloat64(x constant.Value) bool {
	f, _ := constant.Float64Val(x)
	return !math.IsInf(f, 0)
}

func roundFloat64(x constant.Value) constant.Value {
	f, _ := constant.Float64Val(x)
	if !math.IsInf(f, 0) {
		return constant.MakeFloat64(f)
	}
	return nil
}

// representableConst报告x是否可以表示为
// 给定基本类型和配置的值
// 提供（仅适用于int/uint尺寸）。
// None
// 如果四舍五入！=nil，*四舍五入设置为x的四舍五入值
// 可表示的浮点值和复数值，以及整数
// 整数值的值；否则就让它单独呆着。
// 可以为舍入提供第一个参数的地址。
// None
// 如果调用representableConst，则check参数可能为nil
// （间接）通过导出的API调用（可分配到、可转换到）
// 因为这些调用不需要Checker的配置。
func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
	if x.Kind() == constant.Unknown {
		return true // 避免后续错误
	}

	var conf *Config
	if check != nil {
		conf = check.conf
	}

	switch {
	case isInteger(typ):
		x := constant.ToInt(x)
		if x.Kind() != constant.Int {
			return false
		}
		if rounded != nil {
			*rounded = x
		}
		if x, ok := constant.Int64Val(x); ok {
			switch typ.kind {
			case Int:
				var s = uint(conf.sizeof(typ)) * 8
				return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
			case Int8:
				const s = 8
				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
			case Int16:
				const s = 16
				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
			case Int32:
				const s = 32
				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
			case Int64, UntypedInt:
				return true
			case Uint, Uintptr:
				if s := uint(conf.sizeof(typ)) * 8; s < 64 {
					return 0 <= x && x <= int64(1)<<s-1
				}
				return 0 <= x
			case Uint8:
				const s = 8
				return 0 <= x && x <= 1<<s-1
			case Uint16:
				const s = 16
				return 0 <= x && x <= 1<<s-1
			case Uint32:
				const s = 32
				return 0 <= x && x <= 1<<s-1
			case Uint64:
				return 0 <= x
			default:
				unreachable()
			}
		}
		// x不适合int64
		switch n := constant.BitLen(x); typ.kind {
		case Uint, Uintptr:
			var s = uint(conf.sizeof(typ)) * 8
			return constant.Sign(x) >= 0 && n <= int(s)
		case Uint64:
			return constant.Sign(x) >= 0 && n <= 64
		case UntypedInt:
			return true
		}

	case isFloat(typ):
		x := constant.ToFloat(x)
		if x.Kind() != constant.Float {
			return false
		}
		switch typ.kind {
		case Float32:
			if rounded == nil {
				return fitsFloat32(x)
			}
			r := roundFloat32(x)
			if r != nil {
				*rounded = r
				return true
			}
		case Float64:
			if rounded == nil {
				return fitsFloat64(x)
			}
			r := roundFloat64(x)
			if r != nil {
				*rounded = r
				return true
			}
		case UntypedFloat:
			return true
		default:
			unreachable()
		}

	case isComplex(typ):
		x := constant.ToComplex(x)
		if x.Kind() != constant.Complex {
			return false
		}
		switch typ.kind {
		case Complex64:
			if rounded == nil {
				return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
			}
			re := roundFloat32(constant.Real(x))
			im := roundFloat32(constant.Imag(x))
			if re != nil && im != nil {
				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
				return true
			}
		case Complex128:
			if rounded == nil {
				return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
			}
			re := roundFloat64(constant.Real(x))
			im := roundFloat64(constant.Imag(x))
			if re != nil && im != nil {
				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
				return true
			}
		case UntypedComplex:
			return true
		default:
			unreachable()
		}

	case isString(typ):
		return x.Kind() == constant.String

	case isBoolean(typ):
		return x.Kind() == constant.Bool
	}

	return false
}

// representable检查常量操作数在给定的
// 基本类型。
func (check *Checker) representable(x *operand, typ *Basic) {
	v, code := check.representation(x, typ)
	if code != 0 {
		check.invalidConversion(code, x, typ)
		x.mode = invalid
		return
	}
	assert(v != nil)
	x.val = v
}

// 表示返回常量操作数x的表示形式，作为
// 基本类型。
// None
// 如果没有这样的表示，它将返回一个非零错误代码。
func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, errorCode) {
	assert(x.mode == constant_)
	v := x.val
	if !representableConst(x.val, check, typ, &v) {
		if isNumeric(x.typ) && isNumeric(typ) {
			// 数字转换：错误消息
			// None
			// 整数->整数：溢出
			// 整数->浮点：溢出（实际上不可能）
			// 浮点->整数：截断
			// 浮动->浮动：溢出
			// None
			if !isInteger(x.typ) && isInteger(typ) {
				return nil, _TruncatedFloat
			} else {
				return nil, _NumericOverflow
			}
		}
		return nil, _InvalidConstVal
	}
	return v, 0
}

func (check *Checker) invalidConversion(code errorCode, x *operand, target Type) {
	msg := "cannot convert %s to %s"
	switch code {
	case _TruncatedFloat:
		msg = "%s truncated to %s"
	case _NumericOverflow:
		msg = "%s overflows %s"
	}
	check.errorf(x, code, msg, x, target)
}

// UpdateExprtType将x的类型更新为typ并调用自身
// 对x的操作数进行递归，具体取决于表达式类型。
// 如果typ仍然是非类型化的，而不是最终类型，则updateExprtType
// 仅更新x记录的非类型化类型，并可能更新其
// 操作数。否则（即，typ不再是非类型化类型，
// 或者是x的最终类型），记录类型和值。
// 此外，如果x是常数，则它必须表示为典型值，
// 如果x是非常量的（以前未类型化）lhs操作数
// shift，它必须是整数值。
// None
func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
	old, found := check.untyped[x]
	if !found {
		return // 无事可做
	}

	// 如有必要，更新x的操作数
	switch x := x.(type) {
	case *ast.BadExpr,
		*ast.FuncLit,
		*ast.CompositeLit,
		*ast.IndexExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.StarExpr,
		*ast.KeyValueExpr,
		*ast.ArrayType,
		*ast.StructType,
		*ast.FuncType,
		*ast.InterfaceType,
		*ast.MapType,
		*ast.ChanType:
		// 这些表达式从来都是非类型化的-无需任何操作。
		// 相应的子表达式得到了它们的最终类型
		// 分配或使用时。
		if debug {
			check.dump("%v: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
			unreachable()
		}
		return

	case *ast.CallExpr:
		// 导致非类型化常数（例如，内置复合体）。
		// 各个调用负责调用updateExprtType
		// 如有必要，请参阅。

	case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
		// 表示常量、常量文字的标识符，
		// 或限定标识符（导入的非类型化常量）。
		// 没有要处理的操作数。

	case *ast.ParenExpr:
		check.updateExprType(x.X, typ, final)

	case *ast.UnaryExpr:
		// 如果x是常数，则操作数是常数。
		// 操作数不需要更新，因为它们
		// 永远不要将“物化”为类型化的值。如果
		// 在非类型化映射中，它们将被处理
		// 在类型检查结束时。
		if old.val != nil {
			break
		}
		check.updateExprType(x.X, typ, final)

	case *ast.BinaryExpr:
		if old.val != nil {
			break // 有关一元表达式，请参见注释
		}
		if isComparison(x.Op) {
			// 结果类型与操作数类型无关
			// 并且操作数类型必须具有final类型。
		} else if isShift(x.Op) {
			// 结果类型仅取决于lhs操作数。
			// 检查班次时更新了rhs类型。
			check.updateExprType(x.X, typ, final)
		} else {
			// 操作数类型与结果类型匹配。
			check.updateExprType(x.X, typ, final)
			check.updateExprType(x.Y, typ, final)
		}

	default:
		unreachable()
	}

	// 如果新类型不是final并且仍然没有类型化，只需
	// 更新记录的类型。
	if !final && isUntyped(typ) {
		old.typ = asBasic(typ)
		check.untyped[x] = old
		return
	}

	// 否则我们将使用final（类型化或非类型化类型）。
	// 将其从尚未类型化的表达式映射中删除。
	delete(check.untyped, x)

	if old.isLhs {
		// 如果x是移位的lhs，则其最终类型必须为整数。
		// 我们已经从轮班检查中知道它是可代表的
		// 如果它是常量，则为整数。
		if !isInteger(typ) {
			check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s (type %s) must be integer", x, typ)
			return
		}
		// 即使我们有一个整数，如果这个值是常数，我们也可以
		// 还必须检查它是否可以作为特定的
		// 请求的int类型（was问题#22969）。从这里掉下去。
	}
	if old.val != nil {
		// 如果x是常数，则它必须表示为典型值。
		c := operand{old.mode, x, old.typ, old.val, 0}
		check.convertUntyped(&c, typ)
		if c.mode == invalid {
			return
		}
	}

	// 一切正常，记录x的最终类型和值。
	check.recordTypeAndValue(x, old.mode, typ, old.val)
}

// updateExprVal将x的值更新为val。
func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) {
	if info, ok := check.untyped[x]; ok {
		info.val = val
		check.untyped[x] = info
	}
}

// convertUntyped尝试将非类型化值的类型设置为目标类型。
func (check *Checker) convertUntyped(x *operand, target Type) {
	newType, val, code := check.implicitTypeAndValue(x, target)
	if code != 0 {
		check.invalidConversion(code, x, target.Underlying())
		x.mode = invalid
		return
	}
	if val != nil {
		x.val = val
		check.updateExprVal(x.expr, val)
	}
	if newType != x.typ {
		x.typ = newType
		check.updateExprType(x.expr, newType, false)
	}
}

// implicitTypeAndValue在上下文中使用时返回x的隐式类型
// 其中目标类型是预期的。如果不支持这种隐式转换
// 可能的话，它返回一个nil类型和非零错误代码。
// None
// 如果x是常量操作数，则返回的常量。值将是
// 在此上下文中表示x。
func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, errorCode) {
	target = expand(target)
	if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
		return x.typ, nil, 0
	}

	if isUntyped(target) {
		// x和目标都是非类型化的
		xkind := x.typ.(*Basic).kind
		tkind := target.(*Basic).kind
		if isNumeric(x.typ) && isNumeric(target) {
			if xkind < tkind {
				return target, nil, 0
			}
		} else if xkind != tkind {
			return nil, nil, _InvalidUntypedConversion
		}
		return x.typ, nil, 0
	}

	switch t := optype(target).(type) {
	case *Basic:
		if x.mode == constant_ {
			v, code := check.representation(x, t)
			if code != 0 {
				return nil, nil, code
			}
			return target, v, code
		}
		// 非常量非类型化值可能显示为
		// 比较结果（非类型bool），中等
		// （延迟选中）移位的rhs操作数，以及
		// 值为零。
		switch x.typ.(*Basic).kind {
		case UntypedBool:
			if !isBoolean(target) {
				return nil, nil, _InvalidUntypedConversion
			}
		case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
			if !isNumeric(target) {
				return nil, nil, _InvalidUntypedConversion
			}
		case UntypedString:
			// 规范和规范不允许非常量非类型化字符串值
			// 不应在正常的类型检查过程中发生，但此路径是
			// 可通过AssignableTo API访问。
			if !isString(target) {
				return nil, nil, _InvalidUntypedConversion
			}
		case UntypedNil:
			// 不安全。指针是包含nil的基本类型。
			if !hasNil(target) {
				return nil, nil, _InvalidUntypedConversion
			}
			// 将nil的类型保留为UntypedNil：请参见#13061。
			return Typ[UntypedNil], nil, 0
		default:
			return nil, nil, _InvalidUntypedConversion
		}
	case *_Sum:
		ok := t.is(func(t Type) bool {
			target, _, _ := check.implicitTypeAndValue(x, t)
			return target != nil
		})
		if !ok {
			return nil, nil, _InvalidUntypedConversion
		}
		// 不键入keep nil（was bug#39755）
		if x.isNil() {
			return Typ[UntypedNil], nil, 0
		}
	case *Interface:
		// 值必须具有具体的动态类型。如果该值为零，
		// 保持其非类型化（这对于go-vet之类的工具很重要
		// 需要动态类型进行参数检查，例如，打印
		// 功能）
		if x.isNil() {
			return Typ[UntypedNil], nil, 0
		}
		// 无法将非类型化值分配给非空接口
		check.completeInterface(token.NoPos, t)
		if !t.Empty() {
			return nil, nil, _InvalidUntypedConversion
		}
		return Default(x.typ), nil, 0
	case *Pointer, *Signature, *Slice, *Map, *Chan:
		if !x.isNil() {
			return nil, nil, _InvalidUntypedConversion
		}
		// 保持nil非类型化-请参阅上面的接口注释。
		return Typ[UntypedNil], nil, 0
	default:
		return nil, nil, _InvalidUntypedConversion
	}
	return target, nil, 0
}

func (check *Checker) comparison(x, y *operand, op token.Token) {
	// spec：“在任何比较中，第一个操作数必须是可赋值的
	// 设置为第二个操作数的类型，反之亦然。“
	err := ""
	var code errorCode
	xok, _ := x.assignableTo(check, y.typ, nil)
	yok, _ := y.assignableTo(check, x.typ, nil)
	if xok || yok {
		defined := false
		switch op {
		case token.EQL, token.NEQ:
			// spec:“相等运算符==和！=适用于可比较的操作数。”
			defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
		case token.LSS, token.LEQ, token.GTR, token.GEQ:
			// 规范：排序运算符<、<=、>、和>=适用于已排序的操作数。“
			defined = isOrdered(x.typ) && isOrdered(y.typ)
		default:
			unreachable()
		}
		if !defined {
			typ := x.typ
			if x.isNil() {
				typ = y.typ
			}
			err = check.sprintf("operator %s not defined for %s", op, typ)
			code = _UndefinedOp
		}
	} else {
		err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
		code = _MismatchedTypes
	}

	if err != "" {
		check.errorf(x, code, "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
		x.mode = invalid
		return
	}

	if x.mode == constant_ && y.mode == constant_ {
		x.val = constant.MakeBool(constant.Compare(x.val, op, y.val))
		// 操作数从未具体化；不需要更新
		// 他们的类型。
	} else {
		x.mode = value
		// 操作数现在有了它们的最终类型，在运行时-
		// 时间将成为现实。更新表达式树。
		// 如果当前类型是非类型化的，则物化类型
		// 是相应的默认类型。
		check.updateExprType(x.expr, Default(x.typ), true)
		check.updateExprType(y.expr, Default(y.typ), true)
	}

	// spec：“比较运算符比较两个操作数并产生
	// 非类型化的布尔值。“
	x.typ = Typ[UntypedBool]
}

// 如果e！=nil，它必须是移位表达式；对于非恒定位移，它可能为零。
func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
	// TODO（gri）此函数似乎过于复杂。重访。

	var xval constant.Value
	if x.mode == constant_ {
		xval = constant.ToInt(x.val)
	}

	if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
		// lhs为整数类型或可表示的非类型常量
		// 作为一个整数。无事可做。
	} else {
		// 轮班没有机会
		check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
		x.mode = invalid
		return
	}

	// 说明：“移位表达式中的右操作数必须为整数类型
	// 或者是一个非类型常量，可由uint类型的值表示。”

	// 检查常量是否可由uint表示，但不要转换它们
	// （另见第47243期）。
	if y.mode == constant_ {
		// 为负移位计数提供良好的错误信息。
		yval := constant.ToInt(y.val) // 考虑- 1，1，但不- 1.1
		if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
			check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y)
			x.mode = invalid
			return
		}

		if isUntyped(y.typ) {
			// 注意：检查此处的代表性，而不是开关中的代表性
			// 下面，因为iInteger包含非类型整数（was bug#43697）。
			check.representable(y, Typ[Uint])
			if y.mode == invalid {
				x.mode = invalid
				return
			}
		}
	}

	// 检查RHS是否至少为整数类型。
	switch {
	case isInteger(y.typ):
		if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
			check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
			x.mode = invalid
			return
		}
	case isUntyped(y.typ):
		// 这是不正确的，但保留了先前存在的行为。
		// 另见bug#47410。
		check.convertUntyped(y, Typ[Uint])
		if y.mode == invalid {
			x.mode = invalid
			return
		}
	default:
		check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
		x.mode = invalid
		return
	}

	if x.mode == constant_ {
		if y.mode == constant_ {
			// 如果x或y具有未知值，则结果未知
			if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
				x.val = constant.MakeUnknown()
				// 确保类型正确-请参阅下面的注释
				if !isInteger(x.typ) {
					x.typ = Typ[UntypedInt]
				}
				return
			}
			// rhs必须在恒定位移的合理范围内
			const shiftBound = 1023 - 1 + 52 // 因此，我们可以表示smallestFloat64（见第44057期）
			s, ok := constant.Uint64Val(y.val)
			if !ok || s > shiftBound {
				check.invalidOp(y, _InvalidShiftCount, "invalid shift count %s", y)
				x.mode = invalid
				return
			}
			// lhs可以表示为整数，但不能表示为整数
			// （例如，2.0，非类型化浮点）-这只能发生在非类型化浮点上
			// 非整数数值常量。纠正类型，以便换档
			// 结果为整数类型。
			if !isInteger(x.typ) {
				x.typ = Typ[UntypedInt]
			}
			// x是常数，所以xval！=nil，它必须是Int类型。
			x.val = constant.Shift(xval, op, uint(s))
			x.expr = e
			opPos := x.Pos()
			if b, _ := e.(*ast.BinaryExpr); b != nil {
				opPos = b.OpPos
			}
			check.overflow(x, op, opPos)
			return
		}

		// 具有恒定lhs的非恒定位移
		if isUntyped(x.typ) {
			// 说明：“如果非常量移位的左操作数
			// 表达式是一个非类型化常量，类型为
			// 常量是移位表达式
			// 被其左操作数单独替换。“。
			// None
			// 延迟操作数检查，直到我们知道最终的类型
			// 通过将lhs表达式标记为lhs移位操作数。
			// None
			// 通常（在正确的程序中），lhs表达式
			// 在非类型化映射中。然而，有可能
			// 创建不正确的程序，其中包含相同的表达式
			// 评估两次（通过声明周期），例如
			// 在中确定lhs表达式类型
			// 第一轮，因此从地图上删除，然后
			// 在第二轮中未找到（双重插入
			// 同一个expr节点仍然只会导致
			// 该节点，并且只能删除一次）。
			// 小心并检查是否有人进入。
			// 示例：var e，f=int（1<<“”[f]）
			if info, found := check.untyped[x.expr]; found {
				info.isLhs = true
				check.untyped[x.expr] = info
			}
			// 保持x的类型
			x.mode = value
			return
		}
	}

	// 非常量移位-lhs必须是整数
	if !isInteger(x.typ) {
		check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
		x.mode = invalid
		return
	}

	x.mode = value
}

var binaryOpPredicates opPredicates

func init() {
	// 在init中设置binaryOpPredicates可以避免声明周期。
	binaryOpPredicates = opPredicates{
		token.ADD: isNumericOrString,
		token.SUB: isNumeric,
		token.MUL: isNumeric,
		token.QUO: isNumeric,
		token.REM: isInteger,

		token.AND:     isInteger,
		token.OR:      isInteger,
		token.XOR:     isInteger,
		token.AND_NOT: isInteger,

		token.LAND: isBoolean,
		token.LOR:  isBoolean,
	}
}

// 如果e！=nil，它必须是二进制表达式；对于非常量表达式，它可能为零
// （当为二进制表达式隐式的赋值操作调用时）。
func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) {
	var y operand

	check.expr(x, lhs)
	check.expr(&y, rhs)

	if x.mode == invalid {
		return
	}
	if y.mode == invalid {
		x.mode = invalid
		x.expr = y.expr
		return
	}

	if isShift(op) {
		check.shift(x, &y, e, op)
		return
	}

	check.convertUntyped(x, y.typ)
	if x.mode == invalid {
		return
	}
	check.convertUntyped(&y, x.typ)
	if y.mode == invalid {
		x.mode = invalid
		return
	}

	if isComparison(op) {
		check.comparison(x, &y, op)
		return
	}

	if !check.identical(x.typ, y.typ) {
		// 只有在有有效类型时才报告错误
		// （否则，我们已经在别处报告了一个错误）
		if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
			var posn positioner = x
			if e != nil {
				posn = e
			}
			check.invalidOp(posn, _MismatchedTypes, "mismatched types %s and %s", x.typ, y.typ)
		}
		x.mode = invalid
		return
	}

	if !check.op(binaryOpPredicates, x, op) {
		x.mode = invalid
		return
	}

	if op == token.QUO || op == token.REM {
		// 检查零除数
		if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
			check.invalidOp(&y, _DivByZero, "division by zero")
			x.mode = invalid
			return
		}

		// 检查复除法中的除数下溢（见20227版）
		if x.mode == constant_ && y.mode == constant_ && isComplex(x.typ) {
			re, im := constant.Real(y.val), constant.Imag(y.val)
			re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
			if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
				check.invalidOp(&y, _DivByZero, "division by zero")
				x.mode = invalid
				return
			}
		}
	}

	if x.mode == constant_ && y.mode == constant_ {
		// 如果x或y具有未知值，则结果未知
		if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
			x.val = constant.MakeUnknown()
			// x、 类型不变
			return
		}
		// 强制整数操作数的整数除法
		if op == token.QUO && isInteger(x.typ) {
			op = token.QUO_ASSIGN
		}
		x.val = constant.BinaryOp(x.val, op, y.val)
		x.expr = e
		check.overflow(x, op, opPos)
		return
	}

	x.mode = value
	// x、 类型不变
}

// exprKind描述表达式的类型；那种
// 确定表达式在“语句上下文”中是否有效。
type exprKind int

const (
	conversion exprKind = iota
	expression
	statement
)

// rawExpr类型检查表达式e并用表达式初始化x
// 值或类型。如果发生错误，x.mode将设置为无效。
// 如果提示！=nil，它是复合文字元素的类型。
// None
func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
	if trace {
		check.trace(e.Pos(), "expr %s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", x)
		}()
	}

	kind := check.exprInternal(x, e, hint)
	check.record(x)

	return kind
}

// exprInternal包含表达式类型检查的核心。
// 只能由rawExpr调用。
// None
func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
	// 确保x处于有效状态，以备紧急援助
	// （第5770期）
	x.mode = invalid
	x.typ = Typ[Invalid]

	switch e := e.(type) {
	case *ast.BadExpr:
		goto Error // 以前报告过错误

	case *ast.Ident:
		check.ident(x, e, nil, false)

	case *ast.Ellipsis:
		// 省略号在合法的地方被明确处理
		// （数组复合文字和参数列表）
		check.error(e, _BadDotDotDotSyntax, "invalid use of '...'")
		goto Error

	case *ast.BasicLit:
		switch e.Kind {
		case token.INT, token.FLOAT, token.IMAG:
			check.langCompat(e)
			// 非类型化数值的最大尾数精度
			// 是512位，或者两个整数中的每一个都是4048位
			// 浮点数的小数部分
			// 在go/常数包中准确表示。
			// 比这许多位长的常量文本
			// 没有意义；而过长的常数可能会
			// 消耗大量的空间和时间进行无用的转换。
			// 上限为常量长度，上限为
			// 允许在所有数字之间使用分隔符。
			const limit = 10000
			if len(e.Value) > limit {
				check.errorf(e, _InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value))
				goto Error
			}
		}
		x.setConst(e.Kind, e.Value)
		if x.mode == invalid {
			// 解析器已经建立了语法正确性。
			// 如果我们到达这里，那是因为-/溢出下的数字。
			// TODO（gri）setConst（以及go/常量包）
			// 应返回描述问题的错误。
			check.errorf(e, _InvalidConstVal, "malformed constant: %s", e.Value)
			goto Error
		}

	case *ast.FuncLit:
		if sig, ok := check.typ(e.Type).(*Signature); ok {
			if !check.conf.IgnoreFuncBodies && e.Body != nil {
				// 匿名函数被认为是
				// init表达式/func声明，其中包含
				// 它们：使用现有的包级别声明信息。
				decl := check.decl // 捕获以在下面的闭包中使用
				iota := check.iota // 捕获用于下面的闭合（#22345）
				// 不要立即键入check，因为函数可能会
				// 是函数所指向的类型定义的一部分
				// 正文引用。相反，应尽快进行类型检查，
				// 但在封闭范围内容更改之前（#22992）。
				check.later(func() {
					check.funcBody(decl, "<function literal>", sig, e.Body, iota)
				})
			}
			x.mode = value
			x.typ = sig
		} else {
			check.invalidAST(e, "invalid function literal %s", e)
			goto Error
		}

	case *ast.CompositeLit:
		var typ, base Type

		switch {
		case e.Type != nil:
			// 存在复合文字类型-使用它
			// […]T数组类型只能与复合文字一起出现。
			// 在这里检查他们，这样我们就不必处理。。。一般来说
			if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
				if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
					// 我们有一个“open”[…]T数组类型。
					// 创建长度未知的新ArrayType（-1）
					// 并在分析文本后完成设置。
					typ = &Array{len: -1, elem: check.varType(atyp.Elt)}
					base = typ
					break
				}
			}
			typ = check.typ(e.Type)
			base = typ

		case hint != nil:
			// 不存在复合文字类型-使用提示（封闭类型的元素类型）
			typ = hint
			base, _ = deref(under(typ)) // *T意味着&T{}

		default:
			// TODO（gri）根据上下文提供更好的错误消息
			check.error(e, _UntypedLit, "missing type in composite literal")
			goto Error
		}

		switch utyp := optype(base).(type) {
		case *Struct:
			if len(e.Elts) == 0 {
				break
			}
			fields := utyp.fields
			if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
				// 所有元素都必须有键
				visited := make([]bool, len(fields))
				for _, e := range e.Elts {
					kv, _ := e.(*ast.KeyValueExpr)
					if kv == nil {
						check.error(e, _MixedStructLit, "mixture of field:value and value elements in struct literal")
						continue
					}
					key, _ := kv.Key.(*ast.Ident)
					// 尽早进行所有可能的检查（因错误退出前）
					// 所以我们不会把信息丢在地板上
					check.expr(x, kv.Value)
					if key == nil {
						check.errorf(kv, _InvalidLitField, "invalid field name %s in struct literal", kv.Key)
						continue
					}
					i := fieldIndex(utyp.fields, check.pkg, key.Name)
					if i < 0 {
						check.errorf(kv, _MissingLitField, "unknown field %s in struct literal", key.Name)
						continue
					}
					fld := fields[i]
					check.recordUse(key, fld)
					etyp := fld.typ
					check.assignment(x, etyp, "struct literal")
					// 0<=i<len（字段）
					if visited[i] {
						check.errorf(kv, _DuplicateLitField, "duplicate field name %s in struct literal", key.Name)
						continue
					}
					visited[i] = true
				}
			} else {
				// 任何元素都不必须有键
				for i, e := range e.Elts {
					if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
						check.error(kv, _MixedStructLit, "mixture of field:value and value elements in struct literal")
						continue
					}
					check.expr(x, e)
					if i >= len(fields) {
						check.error(x, _InvalidStructLit, "too many values in struct literal")
						break // 无法继续
					}
					// i<len（字段）
					fld := fields[i]
					if !fld.Exported() && fld.pkg != check.pkg {
						check.errorf(x,
							_UnexportedLitField,
							"implicit assignment to unexported field %s in %s literal", fld.name, typ)
						continue
					}
					etyp := fld.typ
					check.assignment(x, etyp, "struct literal")
				}
				if len(e.Elts) < len(fields) {
					check.error(inNode(e, e.Rbrace), _InvalidStructLit, "too few values in struct literal")
					// 可以继续吗
				}
			}

		case *Array:
			// 如果尚未设置引用的阵列，则防止崩溃。这是第18643期。
			// 这是权宜之计。应使用Checker.objPath报告整个
			// 以源中最早的声明开始的路径。TODO（gri）解决此问题。
			if utyp.elem == nil {
				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
				goto Error
			}
			n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
			// 如果我们有一个长度未知的数组（通常是[…]T数组，但是
			// 数组[n]T，其中n是无效的）现在我们知道了长度并
			// 记录数组的类型（通常通过check.typ完成，而不是
			// 要求[…]T）。我们处理[…]T数组和具有无效
			// 这里的长度是相同的，因为“猜测”的长度是有意义的
			// 后者，如果我们有一个复合文字；e、 g.对于[n]int{1，2，3}
			// 当n因某种原因无效时，可以公平地假设它应该
			// be 3（另请参见Checked.arrayLength和issue#27346）。
			if utyp.len < 0 {
				utyp.len = n
				// e、 如果有复合文字元素，则缺少类型
				// 这本身就是一个省略了类型的复合文字。在里面
				// 这种情况下没有任何记录（没有输入
				// 在那一点上的来源）。
				if e.Type != nil {
					check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
				}
			}

		case *Slice:
			// 如果尚未设置引用的切片，则防止崩溃。
			// 请参见*数组的类似注释。
			if utyp.elem == nil {
				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
				goto Error
			}
			check.indexedElts(e.Elts, utyp.elem, -1)

		case *Map:
			// 如果尚未设置引用的映射，则防止崩溃。
			// 请参见*数组的类似注释。
			if utyp.key == nil || utyp.elem == nil {
				check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
				goto Error
			}
			visited := make(map[interface{}][]Type, len(e.Elts))
			for _, e := range e.Elts {
				kv, _ := e.(*ast.KeyValueExpr)
				if kv == nil {
					check.error(e, _MissingLitKey, "missing key in map literal")
					continue
				}
				check.exprWithHint(x, kv.Key, utyp.key)
				check.assignment(x, utyp.key, "map literal")
				if x.mode == invalid {
					continue
				}
				if x.mode == constant_ {
					duplicate := false
					// 如果键为接口类型，则在检查重复项时，该类型也很重要
					xkey := keyVal(x.val)
					if asInterface(utyp.key) != nil {
						for _, vtyp := range visited[xkey] {
							if check.identical(vtyp, x.typ) {
								duplicate = true
								break
							}
						}
						visited[xkey] = append(visited[xkey], x.typ)
					} else {
						_, duplicate = visited[xkey]
						visited[xkey] = nil
					}
					if duplicate {
						check.errorf(x, _DuplicateLitKey, "duplicate key %s in map literal", x.val)
						continue
					}
				}
				check.exprWithHint(x, kv.Value, utyp.elem)
				check.assignment(x, utyp.elem, "map literal")
			}

		default:
			// 当“使用”所有元素时，解包KeyValueExpr
			// 因为check.use不接受它们
			for _, e := range e.Elts {
				if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
					// 理想情况下，我们也应该“使用”kv.Key，但我们不知道
					// 是否为外部定义的结构键。离去
					// 无论如何转发都可能导致其他错误。放弃吧。
					e = kv.Value
				}
				check.use(e)
			}
			// 如果utyp无效，则以前报告过错误
			if utyp != Typ[Invalid] {
				check.errorf(e, _InvalidLit, "invalid composite literal type %s", typ)
				goto Error
			}
		}

		x.mode = value
		x.typ = typ

	case *ast.ParenExpr:
		kind := check.rawExpr(x, e.X, nil)
		x.expr = e
		return kind

	case *ast.SelectorExpr:
		check.selector(x, e)

	case *ast.IndexExpr:
		if check.indexExpr(x, e) {
			check.funcInst(x, e)
		}
		if x.mode == invalid {
			goto Error
		}

	case *ast.SliceExpr:
		check.sliceExpr(x, e)
		if x.mode == invalid {
			goto Error
		}

	case *ast.TypeAssertExpr:
		check.expr(x, e.X)
		if x.mode == invalid {
			goto Error
		}
		xtyp, _ := under(x.typ).(*Interface)
		if xtyp == nil {
			check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
			goto Error
		}
		check.ordinaryType(x, xtyp)
		// x、 （类型）表达式在类型开关中显式处理
		if e.Type == nil {
			// 不要使用invalidAST，因为这可能发生在生成的AST中
			// go/parser。
			check.error(e, _BadTypeKeyword, "use of .(type) outside type switch")
			goto Error
		}
		T := check.varType(e.Type)
		if T == Typ[Invalid] {
			goto Error
		}
		check.typeAssertion(x, x, xtyp, T)
		x.mode = commaok
		x.typ = T

	case *ast.CallExpr:
		return check.callExpr(x, e)

	case *ast.StarExpr:
		check.exprOrType(x, e.X)
		switch x.mode {
		case invalid:
			goto Error
		case typexpr:
			x.typ = &Pointer{base: x.typ}
		default:
			if typ := asPointer(x.typ); typ != nil {
				x.mode = variable
				x.typ = typ.base
			} else {
				check.invalidOp(x, _InvalidIndirection, "cannot indirect %s", x)
				goto Error
			}
		}

	case *ast.UnaryExpr:
		check.unary(x, e)
		if x.mode == invalid {
			goto Error
		}
		if e.Op == token.ARROW {
			x.expr = e
			return statement // 接收操作可能出现在语句上下文中
		}

	case *ast.BinaryExpr:
		check.binary(x, e, e.X, e.Y, e.Op, e.OpPos)
		if x.mode == invalid {
			goto Error
		}

	case *ast.KeyValueExpr:
		// 键：值表达式在复合文本中处理
		check.invalidAST(e, "no key:value expected")
		goto Error

	case *ast.ArrayType, *ast.StructType, *ast.FuncType,
		*ast.InterfaceType, *ast.MapType, *ast.ChanType:
		x.mode = typexpr
		x.typ = check.typ(e)
		// 注意：rawExpr（exprInternal的调用者）将调用check.recordTypeAndValue
		// 即使check.typ已经调用了它。这两者都可以
		// 记录相同表达式和类型的次数。这也不是一个问题
		// 性能问题，因为我们这里只讨论复合文字
		// 类型，这是比较罕见的。

	default:
		if typeparams.IsListExpr(e) {
			// 捕获意外表达式列表的所有内容
			check.errorf(e, _Todo, "unexpected list of expressions")
		} else {
			panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e))
		}
	}

	// 一切都很顺利
	x.expr = e
	return expression

Error:
	x.mode = invalid
	x.expr = e
	return statement // 避免后续错误
}

func keyVal(x constant.Value) interface{} {
	switch x.Kind() {
	case constant.Bool:
		return constant.BoolVal(x)
	case constant.String:
		return constant.StringVal(x)
	case constant.Int:
		if v, ok := constant.Int64Val(x); ok {
			return v
		}
		if v, ok := constant.Uint64Val(x); ok {
			return v
		}
	case constant.Float:
		v, _ := constant.Float64Val(x)
		return v
	case constant.Complex:
		r, _ := constant.Float64Val(constant.Real(x))
		i, _ := constant.Float64Val(constant.Imag(x))
		return complex(r, i)
	}
	return x
}

// 类型断言检查x.（T）是否合法；xtyp必须是x的类型。
func (check *Checker) typeAssertion(at positioner, x *operand, xtyp *Interface, T Type) {
	method, wrongType := check.assertableTo(xtyp, T)
	if method == nil {
		return
	}
	var msg string
	if wrongType != nil {
		if check.identical(method.typ, wrongType.typ) {
			msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name)
		} else {
			msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
		}
	} else {
		msg = "missing method " + method.name
	}
	check.errorf(at, _ImpossibleAssert, "%s cannot have dynamic type %s (%s)", x, T, msg)
}

// expr类型检查表达式e并用表达式值初始化x。
// 结果必须是单个值。
// 如果发生错误，x.mode将设置为无效。
// None
func (check *Checker) expr(x *operand, e ast.Expr) {
	check.rawExpr(x, e, nil)
	check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
	check.singleValue(x)
}

// multiExpr类似于expr，但结果也可能是一个多值。
func (check *Checker) multiExpr(x *operand, e ast.Expr) {
	check.rawExpr(x, e, nil)
	check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
}

// exprWithHint类型检查表达式e并用表达式值初始化x；
// 提示是复合文字元素的类型。
// 如果发生错误，x.mode将设置为无效。
// None
func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
	assert(hint != nil)
	check.rawExpr(x, e, hint)
	check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
	check.singleValue(x)
}

// exprOrType类型检查表达式或类型e，并使用表达式值或类型初始化x。
// 如果发生错误，x.mode将设置为无效。
// None
func (check *Checker) exprOrType(x *operand, e ast.Expr) {
	check.rawExpr(x, e, nil)
	check.exclude(x, 1<<novalue)
	check.singleValue(x)
}

// 如果x.mode处于modeset并将x.mode设置为无效，则exclude将报告错误。
// 该模式集可以包含1<<novalue，1<<builtin，1<<typexpr中的任何一种。
func (check *Checker) exclude(x *operand, modeset uint) {
	if modeset&(1<<x.mode) != 0 {
		var msg string
		var code errorCode
		switch x.mode {
		case novalue:
			if modeset&(1<<typexpr) != 0 {
				msg = "%s used as value"
			} else {
				msg = "%s used as value or type"
			}
			code = _TooManyValues
		case builtin:
			msg = "%s must be called"
			code = _UncalledBuiltin
		case typexpr:
			msg = "%s is not an expression"
			code = _NotAnExpr
		default:
			unreachable()
		}
		check.errorf(x, code, msg, x)
		x.mode = invalid
	}
}

// 如果x描述元组并将x.mode设置为无效，singleValue将报告错误。
func (check *Checker) singleValue(x *operand) {
	if x.mode == value {
		// 元组类型从不命名-不需要下面的底层类型
		if t, ok := x.typ.(*Tuple); ok {
			assert(t.Len() != 1)
			check.errorf(x, _TooManyValues, "%d-valued %s where single value is expected", t.Len(), x)
			x.mode = invalid
		}
	}
}
